/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 * Description: Opus编解码器实现 - 音频数据的Opus编码和解码
 */

#include "little_test.h"
#include "opus.h"
#include "osal_debug.h"
#include "securec.h"
#include <stdlib.h>
#include <string.h>

/**
 * @brief 初始化Opus编解码器
 * @param codec Opus编解码器指针
 * @return 0成功，其他失败
 */
int opus_codec_init(opus_codec_t *codec)
{
    int error;
    
    if (codec == NULL) {
        osal_printk("[OPUS_CODEC] Invalid codec pointer\n");
        return -1;
    }

    // 初始化结构体
    memset_s(codec, sizeof(opus_codec_t), 0, sizeof(opus_codec_t));

    // 创建Opus编码器
    codec->encoder = opus_encoder_create(LITTLE_TEST_SAMPLE_RATE, 
                                        LITTLE_TEST_CHANNELS, 
                                        OPUS_APPLICATION_VOIP, 
                                        &error);
    if (codec->encoder == NULL || error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to create encoder, error: %d\n", error);
        return -1;
    }

    // 配置编码器参数
    error = opus_encoder_ctl(codec->encoder, OPUS_SET_BITRATE(LITTLE_TEST_OPUS_BITRATE));
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to set bitrate, error: %d\n", error);
        opus_encoder_destroy(codec->encoder);
        return -1;
    }

    // 设置复杂度（0-10，越高质量越好但计算量越大）
    error = opus_encoder_ctl(codec->encoder, OPUS_SET_COMPLEXITY(5));
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to set complexity, error: %d\n", error);
        opus_encoder_destroy(codec->encoder);
        return -1;
    }

    // 设置信号类型为语音
    error = opus_encoder_ctl(codec->encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to set signal type, error: %d\n", error);
        opus_encoder_destroy(codec->encoder);
        return -1;
    }

    // 启用DTX（不连续传输）以节省带宽
    error = opus_encoder_ctl(codec->encoder, OPUS_SET_DTX(1));
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to enable DTX, error: %d\n", error);
        opus_encoder_destroy(codec->encoder);
        return -1;
    }

    // 创建Opus解码器
    codec->decoder = opus_decoder_create(LITTLE_TEST_SAMPLE_RATE, 
                                        LITTLE_TEST_CHANNELS, 
                                        &error);
    if (codec->decoder == NULL || error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to create decoder, error: %d\n", error);
        opus_encoder_destroy(codec->encoder);
        return -1;
    }

    // 分配编码缓冲区
    codec->encode_buffer = (uint8_t *)malloc(LITTLE_TEST_MAX_PACKET_SIZE);
    if (codec->encode_buffer == NULL) {
        osal_printk("[OPUS_CODEC] Failed to allocate encode buffer\n");
        opus_encoder_destroy(codec->encoder);
        opus_decoder_destroy(codec->decoder);
        return -1;
    }

    // 分配解码缓冲区
    codec->decode_buffer = (int16_t *)malloc(LITTLE_TEST_FRAME_SIZE * sizeof(int16_t));
    if (codec->decode_buffer == NULL) {
        osal_printk("[OPUS_CODEC] Failed to allocate decode buffer\n");
        opus_encoder_destroy(codec->encoder);
        opus_decoder_destroy(codec->decoder);
        free(codec->encode_buffer);
        return -1;
    }

    codec->initialized = true;
    
    osal_printk("[OPUS_CODEC] Initialized successfully\n");
    osal_printk("[OPUS_CODEC] Sample rate: %d Hz, Channels: %d, Bitrate: %d bps\n", 
                LITTLE_TEST_SAMPLE_RATE, LITTLE_TEST_CHANNELS, LITTLE_TEST_OPUS_BITRATE);
    
    return 0;
}

/**
 * @brief 反初始化Opus编解码器
 * @param codec Opus编解码器指针
 */
void opus_codec_deinit(opus_codec_t *codec)
{
    if (codec == NULL) {
        return;
    }

    // 销毁编码器
    if (codec->encoder != NULL) {
        opus_encoder_destroy(codec->encoder);
        codec->encoder = NULL;
    }

    // 销毁解码器
    if (codec->decoder != NULL) {
        opus_decoder_destroy(codec->decoder);
        codec->decoder = NULL;
    }

    // 释放缓冲区
    if (codec->encode_buffer != NULL) {
        free(codec->encode_buffer);
        codec->encode_buffer = NULL;
    }

    if (codec->decode_buffer != NULL) {
        free(codec->decode_buffer);
        codec->decode_buffer = NULL;
    }

    codec->initialized = false;
    
    osal_printk("[OPUS_CODEC] Deinitialized\n");
}

/**
 * @brief 编码一帧音频数据
 * @param codec Opus编解码器指针
 * @param pcm 输入的PCM数据
 * @param encoded 输出的编码数据缓冲区
 * @param max_size 编码缓冲区最大大小
 * @return 编码后的数据大小，负数表示错误
 */
int opus_encode_frame(opus_codec_t *codec, const int16_t *pcm, uint8_t *encoded, uint32_t max_size)
{
    if (codec == NULL || !codec->initialized || pcm == NULL || encoded == NULL) {
        osal_printk("[OPUS_CODEC] Invalid parameters for encoding\n");
        return -1;
    }

    if (max_size > LITTLE_TEST_MAX_PACKET_SIZE) {
        max_size = LITTLE_TEST_MAX_PACKET_SIZE;
    }

    // 执行Opus编码
    int encoded_size = opus_encode(codec->encoder, 
                                  pcm, 
                                  LITTLE_TEST_FRAME_SIZE, 
                                  encoded, 
                                  (opus_int32)max_size);
    
    if (encoded_size < 0) {
        osal_printk("[OPUS_CODEC] Encoding failed, error: %d\n", encoded_size);
        return encoded_size;
    }

    // DTX情况下，编码大小可能很小（1-2字节），这是正常的
    if (encoded_size <= 2) {
        // DTX帧，不需要传输
        return 0;
    }

    return encoded_size;
}

/**
 * @brief 解码一帧音频数据
 * @param codec Opus编解码器指针
 * @param encoded 输入的编码数据
 * @param encoded_size 编码数据大小
 * @param pcm 输出的PCM数据缓冲区
 * @return 解码后的样本数，负数表示错误
 */
int opus_decode_frame(opus_codec_t *codec, const uint8_t *encoded, uint32_t encoded_size, int16_t *pcm)
{
    if (codec == NULL || !codec->initialized || pcm == NULL) {
        osal_printk("[OPUS_CODEC] Invalid parameters for decoding\n");
        return -1;
    }

    int decoded_samples;
    
    if (encoded == NULL || encoded_size == 0) {
        // 包丢失情况，使用FEC（前向纠错）解码
        decoded_samples = opus_decode(codec->decoder, 
                                     NULL, 
                                     0, 
                                     pcm, 
                                     LITTLE_TEST_FRAME_SIZE, 
                                     0);  // 不使用FEC
    } else {
        // 正常解码
        decoded_samples = opus_decode(codec->decoder, 
                                     encoded, 
                                     (opus_int32)encoded_size, 
                                     pcm, 
                                     LITTLE_TEST_FRAME_SIZE, 
                                     0);  // 不使用FEC
    }
    
    if (decoded_samples < 0) {
        osal_printk("[OPUS_CODEC] Decoding failed, error: %d\n", decoded_samples);
        return decoded_samples;
    }

    if (decoded_samples != LITTLE_TEST_FRAME_SIZE) {
        osal_printk("[OPUS_CODEC] Warning: decoded %d samples, expected %d\n", 
                    decoded_samples, LITTLE_TEST_FRAME_SIZE);
    }

    return decoded_samples;
}

/**
 * @brief 重置Opus编解码器状态
 * @param codec Opus编解码器指针
 * @return 0成功，其他失败
 */
int opus_codec_reset(opus_codec_t *codec)
{
    if (codec == NULL || !codec->initialized) {
        return -1;
    }

    int error;
    
    // 重置编码器
    error = opus_encoder_ctl(codec->encoder, OPUS_RESET_STATE);
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to reset encoder, error: %d\n", error);
        return -1;
    }

    // 重置解码器
    error = opus_decoder_ctl(codec->decoder, OPUS_RESET_STATE);
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to reset decoder, error: %d\n", error);
        return -1;
    }

    osal_printk("[OPUS_CODEC] Reset successfully\n");
    return 0;
}

/**
 * @brief 获取编码器延迟
 * @param codec Opus编解码器指针
 * @return 延迟样本数，负数表示错误
 */
int opus_codec_get_lookahead(opus_codec_t *codec)
{
    if (codec == NULL || !codec->initialized) {
        return -1;
    }

    opus_int32 lookahead;
    int error = opus_encoder_ctl(codec->encoder, OPUS_GET_LOOKAHEAD(&lookahead));
    if (error != OPUS_OK) {
        osal_printk("[OPUS_CODEC] Failed to get lookahead, error: %d\n", error);
        return -1;
    }

    return (int)lookahead;
}